﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using MySql.Data;
using MySql.Data.MySqlClient;
using System.Data.Common;
using System.Data;

namespace Quick.Lib.Db
{
    /// <summary>
    /// 参数化命令创建工厂
    /// </summary>
    public class CommandFactory
    {
        /// <summary>
        /// 表名
        /// </summary>
        private string TableName;

        /// <summary>
        /// 存储定义的所有 IDbDataParameter 值对象
        /// </summary>
        private List<IDbDataParameter> listSqlParameters = new List<IDbDataParameter>();

        /// <summary>
        /// 存储定义的所有 IDbDataParameterValue 值对象
        /// </summary>
        private List<ParaValue> listDbValues = new List<ParaValue>();

        /// <summary>
        /// 数据库类型
        /// </summary>
        private DataSourceType dataSourceType = DataSourceType.UNKNOW;

        public CommandFactory(string name)
        {
            this.TableName = name;
        }

        public CommandFactory(string name, DataSourceType type)
        {
            this.TableName = name;
            this.dataSourceType = type;
        }

        public static CommandFactory createFactory(string name, DataSourceType type)
        {
            return new CommandFactory(name, type);
        }

        public IDbDataParameter createParameter(ParaValue value)
        {
            switch (this.dataSourceType)
            {
                case DataSourceType.MySql:

                    MySqlParameter parameter = new MySqlParameter();
                    parameter.ParameterName = value.Name;
                    parameter.Value = value.Value;
                    parameter.DbType = value.Type;
                    if (value.Size > 0)
                    {
                        parameter.Size = value.Size;
                    }
                    return parameter;

                default:
                    throw new Exception("没有指定数据库类型");
            }
        }

        public IDbDataParameter createParameter(string name , object value)
        {
            ParaValue para = new ParaValue()
            {
                Name = name, Value = value
            };
            return createParameter(para);
        }

        public IDbDataParameter AddParam(string name, ParaValue parameter)
        {
            parameter.Name = name;
            IDbDataParameter para = createParameter(parameter);

            this.listDbValues.Add(parameter);
            this.listSqlParameters.Add(para);
            return para;
        }

        public IDbDataParameter AddParam(string name, object value)
        {
            return AddParam(name, value, DbType.String, -1, ParaOperator.AUTO);
        }

        public IDbDataParameter AddParam(string name, object value, ParaOperator valueOperator)
        {
            return AddParam(name, value, DbType.String, -1, valueOperator);
        }

        public IDbDataParameter AddParam(string name, object value, DbType type, int size, ParaOperator valueOperator)
        {
            ParaValue obj = new ParaValue();
            obj.Name = name;
            obj.Value = value;
            obj.Size = size;
            obj.Type = type;
            obj.valueOperator = valueOperator;

            return AddParam(name, obj);
        }

        public CommandData GetSelectCommand(string fields , string where , List<IDbDataParameter> conditionParameters)
        {
            if (fields == null)
                fields = "*";

            if(where == null)
            {
                where = "1=1";
            }

            if(conditionParameters == null)
            {
                conditionParameters = new List<IDbDataParameter>();
            }
            
            string sql = string.Format("select {0} from {1} where {2};", fields, this.TableName, where);
            return new CommandData(sql, conditionParameters.ToArray());
        }

        public CommandData GetSelectCommand(string fields, string where)
        {
            string sql = string.Format("select {0} from {1} where {2};", fields, this.TableName, where);
            return new CommandData(sql, null);
        }

        public CommandData GetInsertCommand()
        {
            CommandData command = new CommandData();
            List<IDbDataParameter> parameters = new List<IDbDataParameter>();
            List<string> fieldNames = new List<string>();
            List<string> fieldValues = new List<string>();

            foreach (IDbDataParameter item in this.listSqlParameters)
            {
                fieldNames.Add(item.ParameterName);
                fieldValues.Add("@" + item.ParameterName);
            }

            string sql = String.Format("insert into {0}({1}) values({2});",
                this.TableName,
                String.Join(",", fieldNames.ToArray()),
                String.Join(",", fieldValues.ToArray())
            );

            command.SQLString = sql;
            command.Parameters = this.listSqlParameters.ToArray();

            return command;
        }

        public CommandData GetUpdateCommand(string where, List<IDbDataParameter> conditionParameters)
        {
            CommandData command = new CommandData();

            StringBuilder sb = new StringBuilder();

            List<IDbDataParameter> parameters = new List<IDbDataParameter>();
            List<string> setNameValues = new List<string>();
            List<string> strWhereConditions = new List<string>();

            foreach (ParaValue item in this.listDbValues)
            {
                string str = string.Format("{0}=@{1}", item.Name, item.Name);
                if (item.valueOperator == ParaOperator.INCREMENT_IN_UPDATE)
                {
                    str = string.Format("{0}={0}+{1}", item.Name, item.Value);
                }
                if (item.valueOperator == ParaOperator.DECREAMENT_IN_UPDATE)
                {
                    str = string.Format("{0}={0}-{1}", item.Name, item.Value);
                }
                setNameValues.Add(str);
            }

            foreach (IDbDataParameter item in conditionParameters)
            {
                strWhereConditions.Add(string.Format("{0}=@{0}", item.ParameterName));
            }

            string sql = String.Format("update {0} set {1} where {2};",
                this.TableName,
                String.Join(",", setNameValues.ToArray()),
                String.Join(",", strWhereConditions.ToArray())
            );

            command.SQLString = sql;
            command.Parameters = this.listSqlParameters == null ? null : this.listSqlParameters.ToArray();

            return command;
        }

        /// <summary>
        /// 获取相关Delete命令的 CommandData 信息
        /// </summary>
        /// <returns></returns>
        public CommandData GetDeleteCommand(string where, List<IDbDataParameter> conditionParameters)
        {
            List<string> strWhereConditions = new List<string>();
            foreach (IDbDataParameter item in conditionParameters)
            {
                strWhereConditions.Add(string.Format("{0}=@{0}", item.ParameterName));
            }
            string sql = string.Format("delete {0} where {1}", this.TableName, where);
            CommandData data = new CommandData(sql, conditionParameters == null ? null : conditionParameters.ToArray());

            return data;
        }
    }
}
